package network.server;

import java.io.IOException;
import java.net.Socket;

import state.Globals;

import messages.DeregistrationMessage;

/**
 * Base class for handling connections, closes the 
 * 
 * @author Ian Doerr
 */
public abstract class SocketThread implements Runnable {
    
    private Thread runner;
    private ConnectionListenerThread parent;
    
    protected boolean shouldContinue = true;
    protected Socket remoteSock;
    
    /**
     * Initializes a new SocketThread with the given parent socket and remote socket.
     * 
     * @param parent
     * @param remoteSock
     */
    public SocketThread(ConnectionListenerThread parent, Socket remoteSock)
    {
    	this.parent = parent;
        this.runner = new Thread(this);
        
        this.remoteSock = remoteSock;
    }
    
    /**
     * Abstract method where subclasses perform their work
     */
    public abstract void runThread();
    
    @Override
    /**
     * Performs some logging, calls the runThread() method, and closes / cleans up when done
     */
    public void run()
    {
        
    	if (Globals.isDebug())
    	{
    		Globals.getLogger().log("Starting up a SocketThread connected to: " + remoteSock.getInetAddress() + ":" + remoteSock.getPort());
    	}
    	
        runThread(); //execute the thread's run method
        
        if (Globals.isDebug())
        {
        	Globals.getLogger().log("Shutting down a SocketThread connected to: " + remoteSock.getInetAddress() + ":" + remoteSock.getPort());
        }
        
        //attempt to write out a deregistration message, but only if the socket isn't closed
        try
        {
            if (!remoteSock.isClosed())
            {
            	if (Globals.isDebug())
            	{
            		Globals.getLogger().log("Sending out Deregistration Message");
            	}
            	
                DeregistrationMessage message = new DeregistrationMessage();
                
                remoteSock.getOutputStream().write(message.toByteArray());
            }
        }
        catch (IOException e)
        {
            Globals.getLogger().error("Could not send the deregistration message!", e);
        }
        finally
        {
            try
            {
                remoteSock.close();
            }
            catch (IOException e)
            {
                //NOOP - don't really care
            }
        }
        
        parent.removeChild(this);
    }
    
    /**
     * Returns the reference to the remote socket.
     * 
     * @return
     */
    public Socket getRemoteSocket()
    {
        return remoteSock;
    }
    
    /**
     * starts the handling thread
     */
    public void start()
    {
        runner.start();
    }
    
    /**
     * Returns the running thread
     * 
     * @return
     */
    public Thread getThread()
    {
    	return runner;
    }
    
    /**
     * Returns this thread's parent.
     * 
     * @return
     */
    public ConnectionListenerThread getParent()
    {
        return parent;
    }
    
    /**
     * Shuts down the thread
     */
    public void shutdownThread()
    {
        shouldContinue = false;
    }
    
}
